﻿using System;
using System.Diagnostics;
using System.Reflection;

using zijian666.Converts.Abstractions;
using zijian666.Converts.Convertor.Base;
using zijian666.Converts.Core;

namespace zijian666.Converts.Extensions;

/// <summary>
/// 转换器扩展方法
/// </summary>
public static class ConvertContextExtensions
{
    /// <summary>
    /// 获取 <seealso cref="IConvertor{T}"/> 并执行 <seealso cref="IConvertor{T}.Convert(IConvertContext, object?)"/>
    /// </summary>
    /// <typeparam name="T">转换器泛型</typeparam>
    /// <param name="context">上下文</param>
    /// <param name="value">待转换的值</param>
    /// <returns></returns>
    public static ConvertResult<T> Convert<T>(this IConvertContext context, object? value)
    {
        if (context is null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        var convertor = context.GetConvertor<T>();
        if (convertor is null)
        {
            return ExceptionHelper.CantBuildConvertor(typeof(T).GetFriendlyName(), nameof(ResourceStrings.CONVERTOR_NOT_FOUND), context?.Settings?.CultureInfo);
        }
        return convertor.Convert(context, value);
    }

    /// <summary>
    /// 获取 <paramref name="type"/>类型的转换器, 并代理为 <seealso cref="IConvertor{T}"/>, 然后执行
    /// </summary>
    /// <param name="context"></param>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static ConvertResult<object> Convert(this IConvertContext context, Type type, object? value)
    {
        if (type.IsGenericTypeDefinition)
        {
            return ExceptionHelper.CantBuildConvertor(type.GetFriendlyName(), nameof(ResourceStrings.CLASS_IS_GENERIC_TYPE_DEFINITION), context.Settings.CultureInfo);
        }
        return (ConvertResult<object>)typeof(ProxyConvertor<,>).MakeGenericType(type, typeof(object)).GetMethod("Convert", BindingFlags.Static | BindingFlags.Public)!.Invoke(null, [context, value])!;
    }

    /// <summary>
    /// 获取指定输出类型的转换器
    /// </summary>
    /// <typeparam name="T">转换器输出类型</typeparam>
    /// <param name="context">转换上下文</param>
    /// <returns></returns>
    public static IConvertor<T>? GetConvertor<T>(this IConvertContext context)
        => context?.Settings.GetConvertor<T>(context);

    /// <summary>
    /// 转换失败
    /// </summary>
    /// <param name="context">转换上下文</param>
    /// <param name="convertor">当前转换器</param>
    /// <param name="input">待转换的值</param>
    /// <param name="e">转换失败异常</param>
    /// <returns></returns>
    public static InvalidCastException ConvertFail<T1, T2>(this IConvertContext context, BaseConvertor<T1> convertor, T2 input, Exception? e = null)
        => ExceptionHelper.ConvertFail(input, convertor.TypeFriendlyName, context.Settings.CultureInfo, e);

    /// <summary>
    /// 获取设置上下文中的选项
    /// </summary>
    /// <typeparam name="T">选项值类型</typeparam>
    /// <param name="context">转换上下文</param>
    /// <param name="key">选项键</param>
    /// <param name="defaultValue">如果对应选项不存在，则返回该值</param>
    /// <returns></returns>
    public static T GetOption<T>(this IConvertContext context, string key, T defaultValue) => context[key] is T t ? t : defaultValue;

    public static void Log(this IConvertContext context, string name, object? value)
    {
        if (context["TRACE"] is DiagnosticListener logger && logger.IsEnabled(name, value))
        {
            logger.Write(name, value);
        }
    }

    public static void Log(this IConvertContext context, string name, Func<object?> func)
    {
        if (context["TRACE"] is DiagnosticListener logger && logger.IsEnabled(name))
        {
            logger.Write(name, func());
        }
    }
}
